/*
 * $Id: NavigationController.java 134 2009-07-13 10:02:12Z donbeave $
 */

package labour.manager.client.mvc;

import labour.concept.client.data.Locale;
import labour.concept.client.data.ObjectText;
import labour.concept.client.data.ObjectType;
import labour.concept.engine.client.data.EngineManager;
import labour.concept.engine.client.data.EngineObject;
import labour.concept.engine.client.data.Site;
import labour.manager.client.AppEvents;
import labour.manager.client.NavigationEvents;
import labour.manager.client.data.InfoStructureLoader;
import labour.manager.client.data.InfoStructureProxy;
import labour.manager.client.data.InfoStructureStore;

import com.extjs.gxt.ui.client.Registry;
import com.extjs.gxt.ui.client.data.LoadEvent;
import com.extjs.gxt.ui.client.data.Loader;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.data.TreeLoadEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.extjs.gxt.ui.client.mvc.Dispatcher;
import com.extjs.gxt.ui.client.widget.treepanel.TreePanel;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class NavigationController extends Controller {

  public static String INFO_LOADER = "NavigationController.INFO_LOADER";
  public static String INFO_STORE = "NavigationController.INFO_STORE";

  private NavigationView navigationView;

  private InfoStructureLoader infoLoader;
  private InfoStructureStore infoStore;

  public NavigationController() {
    registerEventTypes(AppEvents.Ready);
    registerEventTypes(NavigationEvents.Refresh);
    registerEventTypes(NavigationEvents.ShowProperties);
    registerEventTypes(NavigationEvents.CreateObject);
    registerEventTypes(NavigationEvents.DeleteObject);
  }

  public void initialize() {
    navigationView = new NavigationView(this);
  }

  public void handleEvent(AppEvent event) {
    if (event.getType() == AppEvents.Ready) {
      onReady();
    }
    else if (event.getType() == NavigationEvents.Refresh) {
      if (event.getData() instanceof Site) {
        onRefresh((Site) event.getData());
      }
      else if (event.getData() instanceof Locale) {
        onRefresh((Locale) event.getData());
      }
      else if (event.getData() instanceof ObjectText) {
        onRefresh((ObjectText) event.getData());
      }
    }
    else if (event.getType() == NavigationEvents.ShowProperties) {
      forwardToView(navigationView, event);
    }
    else if (event.getType() == NavigationEvents.CreateObject) {
      onCreateObject((ObjectType) event.getData(), (String) event.getData("Name"), (Locale) event.getData("Locale"), (EngineObject) event.getData("Parent"));
    }
    else if (event.getType() == NavigationEvents.DeleteObject) {
      onDeleteObject((ObjectText) event.getData());
    }
  }

  protected void onRefresh() {
    infoLoader.load();
  }

  protected void onRefresh(Site site) {
    infoLoader.loadChildren(site);
  }

  protected void onRefresh(Locale locale) {
    infoLoader.loadChildren(locale);
  }

  protected void onRefresh(ObjectText text) {
    infoLoader.loadChildren(text);
  }

  protected void onCreateObject(ObjectType type, String name, final Locale locale, final EngineObject parent) {
    EngineManager manager = Registry.get(AppController.MANAGER);

    EngineObject object;

    if (parent == null) {
      object = manager.createObject(type, name, locale);
    } else {
      object = parent.createChild(type, name, locale);
    }

    object.save(new AsyncCallback<EngineObject>() {
      public void onFailure(Throwable caught) {
        AppEvent event = new AppEvent(AppEvents.Error);
        event.setData(caught);

        Dispatcher.forwardEvent(event);
      }

      public void onSuccess(EngineObject result) {
        AppEvent event = new AppEvent(NavigationEvents.Refresh);

        if (parent != null) {
          event.setData(parent.getData(locale));
        } else {
          event.setData(locale);
        }

        Dispatcher.forwardEvent(event);
      }
    });
  }

  protected void onDeleteObject(final ObjectText text) {
    text.getObject().delete(new AsyncCallback<EngineObject>() {
      public void onFailure(Throwable caught) {
        AppEvent event = new AppEvent(AppEvents.Error);
        event.setData(caught);

        Dispatcher.forwardEvent(event);
      }

      public void onSuccess(EngineObject result) {
        final AppEvent event = new AppEvent(NavigationEvents.Refresh);

        if (text.getObject().hasParent()) {
          // getting parent
          text.getObject().loadParent(new AsyncCallback<EngineObject>() {
            public void onFailure(Throwable caught) {
              AppEvent event = new AppEvent(AppEvents.Error);
              event.setData(caught);

              Dispatcher.forwardEvent(event);
            }

            public void onSuccess(EngineObject parent) {
              event.setData(parent.getData(text.getLocale()));

              Dispatcher.forwardEvent(event);
            }
          });
        } else {
          event.setData(text.getLocale());

          Dispatcher.forwardEvent(event);
        }
      }
    });
  }

  protected void onReady() {
    infoLoader = new InfoStructureLoader(new InfoStructureProxy((EngineManager) Registry.get(AppController.MANAGER)));
    infoStore = new InfoStructureStore(infoLoader);

    Registry.register(INFO_LOADER, infoLoader);
    Registry.register(INFO_STORE, infoStore);

    // creating panel and tree
    forwardToView(navigationView, new AppEvent(AppEvents.Ready));

    final TreePanel<ModelData> treePanel = Registry.get(NavigationView.INFO_TREE);

    infoLoader.addListener(Loader.Load, new Listener<TreeLoadEvent>() {
      public void handleEvent(TreeLoadEvent loadEvent) {
        ModelData config = loadEvent.getConfig();

        if (config != null) {
          if (!treePanel.isExpanded(config)) {
            treePanel.toggle(config);
          }
        }
      }
    });

    final EngineManager manager = Registry.get(AppController.MANAGER);

    // TODO нужны ли эти махинации с локалью и сайтом ???
    infoLoader.addListener(Loader.BeforeLoad, new Listener<LoadEvent>() {
      public void handleEvent(LoadEvent be) {
        ModelData config = (ModelData) be.getConfig();

        if (config instanceof Site) {
          manager.setMainSite((Site) config);
        }

        if (config instanceof Locale) {
//          manager.setDefaultLocale((Locale) config);
        }
      }
    });

    // loading data (sites list)
    infoLoader.load();
  }

}